package edu.towson.cosc.cosc455.mdapice.compiler;

import java.util.ArrayList;

/**
 * COSC 455 Programming Languages: Implementation and Design.
 * 
 * A Simple Semantic Analyzer interfaced by Josh Dehlinger (2013) and
 * modified by Michelle D'Apice (2014).
 * 
 * Takes abstract parse tree from Syntax Analyzer and translates it into HTML5.
 * 
 * @author Michelle D'Apice
 */

public class MySemanticAnalyzer {
	
	//once there are no semantic errors, this will be translated into the HTML, sent to the compiler and written to the outputfile
	public static ArrayList<String> finalTree = new ArrayList<String>();
	//a stack to keep track of the variable names within each scope
	public static ArrayList<String> varnameStack = new ArrayList<String>();
	//a stack to keep track of the variable definitions within each scope
	public static ArrayList<String> varvalStack = new ArrayList<String>();
	//a stack to keep track of which block the other two stacks are pointing to
	public static ArrayList<String> blockStack = new ArrayList<String>();
	//a counter to keep track of the number of variables made within each scope
	public static int counter = 0;
	//an integer to run through the parseTree created by the SyntaxAnalyzer
	public static int index = 0;
	//a list to keep track of the variable tags that must be deleted before sending to compiler
	public static ArrayList<Integer> indexestobedeleted = new ArrayList<Integer>();
	
	//set(int index, E element) 
	
	public void semanticAn(){
		
		//copying parseTree into finalTree
		for(int i = 0; i < MyCompiler.parseTree.size(); i++){
			finalTree.add(MyCompiler.parseTree.get(i));		
		}		
		
		//****START****//
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.DOC_BEGIN)){ //scope 1
			finalTree.set(index, "<html> ");
			index++;
			semanCode();
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.DOC_END)){
				finalTree.set(index, "</html> ");
			}
		}
		
		//*Use indexestobedeleted to get rid of tags associated with variables
		/*System.out.println("\nIndexes to be Deleted:");
		for(Integer value : indexestobedeleted){
			System.out.println(value);
		}*/
		
		
	}//end of semanticAn
	
	public void semanCode(){
		//within the scope of the head tag - global variables
		
		//variable
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.VAR_BEGIN)){
			//define
			for(int i = 0; i < 5; i++){
				indexestobedeleted.add(index + i);
			}
			varnameStack.add(MyCompiler.parseTree.get(index+1));
			varvalStack.add(MyCompiler.parseTree.get(index+3));
			blockStack.add(LexicalTokens.DOC_BEGIN);
			counter++;
			index += 5;
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.HEAD_BEGIN)){
				head();
				body();
			}
			else{
				body();
			}
		}
		//head
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.HEAD_BEGIN)){
			head();
			define();
			body();
		}
		//comment
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.COMMENT_BEGIN)){
			comment();
			define();
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.HEAD_BEGIN)){
				head();
				body();
			}
			else{
				body();
			}
		}
		//body
		else if((MyCompiler.parseTree.get(index).equals(LexicalTokens.PARA_BEGIN)) || (MyCompiler.parseTree.get(index).equals(LexicalTokens.ITAL_BEGIN))
				|| (MyCompiler.parseTree.get(index).equals(LexicalTokens.BOLD_BEGIN)) || (MyCompiler.parseTree.get(index).equals(LexicalTokens.LIST_BEGIN))
				|| !(MyCompiler.parseTree.get(index).charAt(0) == '#')){
			body();
		}
		
	}//end of semanCode method
	
	public void head(){
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.HEAD_BEGIN)){
			finalTree.set(index, "<head> ");
			index++;
			title();
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.OIC)){
				finalTree.set(index, "</head> ");
				index++;
			}
		}
		
	}//end of head method
	
	public void comment(){
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.COMMENT_BEGIN)){
			finalTree.set(index, "<!-- ");
			index++;
			//text
			index++;
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.TLDR)){
				finalTree.set(index, "--> ");
				index++;
			}
		}
	
	}//end of comment method
	
	public void title(){
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.TITLE_BEGIN)){
			finalTree.set(index, "<title> ");
			index++;
			//text
			index++;
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.MKAY)){
				finalTree.set(index, "</title> ");
				index++;
			}
		}
		
		
	}//end of title method
	
	public void body(){
		//comment
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.COMMENT_BEGIN)){
			comment();
			body();
		}
		//paragraph
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.PARA_BEGIN)){
			paragraph();
			body();
		}
		//bold
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.BOLD_BEGIN)){
			body();
		}
		//italics
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.ITAL_BEGIN)){
			italics();
			body();
		}
		//list
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.LIST_BEGIN)){
			list();
			body();
		}
		//any annotations in inner-text nonterminal/if it's not a tag it is text
		else if(LexicalTokens.innertextList.contains(MyCompiler.parseTree.get(index)) || !(MyCompiler.parseTree.get(index).charAt(0) == '#')){
			innerText();
			body();
		}
	}//end of body method
	
	
	public void bold(){ //SCOPE
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.BOLD_BEGIN)){
			finalTree.set(index, "<b> ");
			index++;
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.VAR_BEGIN)){
				//define
				blockStack.add(LexicalTokens.BOLD_BEGIN);
				for(int i = 0; i < 5; i++){
					indexestobedeleted.add(index + i);
				}
				varnameStack.add(MyCompiler.parseTree.get(index+1));
				varvalStack.add(MyCompiler.parseTree.get(index+3));
				counter++;
				index += 5;
			}
			innerText();
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.MKAY)){
				finalTree.set(index, "</b> ");
				index++;
			}
		}
		
	}
	
	public void italics(){ //SCOPE
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.ITAL_BEGIN)){
			finalTree.set(index, "<i> ");
			index++;
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.VAR_BEGIN)){
				//define
				blockStack.add(LexicalTokens.ITAL_BEGIN);
				for(int i = 0; i < 5; i++){
					indexestobedeleted.add(index + i);
				}
				varnameStack.add(MyCompiler.parseTree.get(index+1));
				varvalStack.add(MyCompiler.parseTree.get(index+3));
				counter++;
				index += 5;
			}
			innerText();
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.MKAY)){
				finalTree.set(index, "</i> ");
				index++;
			}
		}
		
	}
	
	public void newline(){
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.NEWLINE)){
			finalTree.set(index, "<br> ");
			index++;
		}
		
	}
	
	public void audio(){
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.SOUND_BEGIN)){
			finalTree.set(index, "<audio controls> <src=\"");
			index++;
			//text
			index++;
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.MKAY)){
				finalTree.set(index, "\"> </audio> ");
				index++;
			}
		}
		
	}//end of audio method
	
	public void video(){
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.VID_BEGIN)){
			finalTree.set(index, "<iframe src=\"");
			index++;
			//text
			index++;
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.MKAY)){
				finalTree.set(index, "\"/> ");
				index++;
			}
		}
		
	}//end of video method
	
	public void paragraph(){ //SCOPE
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.PARA_BEGIN)){
			finalTree.set(index, "<p> ");
			index++;
			//check for variables
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.VAR_BEGIN)){
				//define
				blockStack.add(LexicalTokens.PARA_BEGIN);
				for(int i = 0; i < 5; i++){
					indexestobedeleted.add(index + i);
				}
				varnameStack.add(MyCompiler.parseTree.get(index+1));
				varvalStack.add(MyCompiler.parseTree.get(index+3));
				counter++;
				index += 5;
			}
			innerPara();
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.OIC)){
				finalTree.set(index, "</p> ");
				index++;
			}
		}
		
		
	}//end of paragraph method
		
	public void innerPara(){
		//bold
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.BOLD_BEGIN)){
			bold();
			innerPara();
		}
		//italics
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.ITAL_BEGIN)){
			italics();
			innerPara();
		}
		//list
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.LIST_BEGIN)){
			list();
			innerPara();
		}
		//newline
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.NEWLINE)){
			newline();
			innerPara();
		}
		//any annotations in inner-text nonterminal/if it's not a tag it is text
		else if(LexicalTokens.innertextList.contains(MyCompiler.parseTree.get(index)) || !(MyCompiler.parseTree.get(index).charAt(0) == '#')){
			innerText();
			innerPara();
		}
		
	}//end of innerPara method
	
	public void list(){
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.LIST_BEGIN)){
			finalTree.set(index, "<ul> ");
			index++;
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.ITEM_BEGIN)){
				finalTree.set(index, "<li> ");
				index++;
				innerList();
				if(MyCompiler.parseTree.get(index).equals(LexicalTokens.MKAY)){
					finalTree.set(index, "</li> ");
					index++;
					item();
					if(MyCompiler.parseTree.get(index).equals(LexicalTokens.OIC)){
						finalTree.set(index, "</ul> ");
						index++;
					}
				}
				
			}
			
		}
		
	}//end of list method
	
	public void innerList(){
		//bold
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.BOLD_BEGIN)){
			bold();
			innerList();
		}
		//italics
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.ITAL_BEGIN)){
			italics();
			innerList();
		}
		//list
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.LIST_BEGIN)){
			list();
			innerList();
		}
		//any annotations in inner-text nonterminal or text
		else if(LexicalTokens.innertextList.contains(MyCompiler.parseTree.get(index)) || !(MyCompiler.parseTree.get(index).charAt(0) == '#')){
			innerText();
			innerList();
		}
		
	}//end of innerList method
	
	public void item(){
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.ITEM_BEGIN)){
			finalTree.set(index, "<li> ");
			index++;
			innerList();
			if(MyCompiler.parseTree.get(index).equals(LexicalTokens.MKAY)){
				finalTree.set(index, "</li> ");
				index++;
				//more items?
				if(MyCompiler.parseTree.get(index).equals(LexicalTokens.ITEM_BEGIN)){
					item();
				}
			}
			
		}
		
	}//end of item method
	
	public void innerText(){
		//visible
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.VISIBLE)){
			use();
			innerText();
		}
		//newline
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.NEWLINE)){
			newline();
			innerText();
		}
		//audio
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.SOUND_BEGIN)){
			audio();
			innerText();
		}
		//video
		else if(MyCompiler.parseTree.get(index).equals(LexicalTokens.VID_BEGIN)){
			video();
			innerText();
		}
		//if it's not any annotations in inner-text nonterminal/if it's not a tag then it is text
		else if(!(LexicalTokens.innertextList.contains(MyCompiler.parseTree.get(index))) && !(MyCompiler.parseTree.get(index).charAt(0) == '#')){
			//text
			index++;
			innerText();
		}
		
	}//end of innerText method
	
	public void define(){
			
		
	}//end of define method
	
	public void use(){
		if(MyCompiler.parseTree.get(index).equals(LexicalTokens.VISIBLE)){
			//get variable value from stacks
			
			if(!blockStack.get(blockStack.size()-1).equals(LexicalTokens.DOC_BEGIN)){
				
			}
			
			if(varnameStack.isEmpty() && varvalStack.isEmpty() && blockStack.isEmpty()){
				System.err.println("STATIC SEMNANTIC ERROR: Cannot use an undefined variable.");
				System.exit(0);
			}
			
			index += 3; //skips over those tags
		}
	}//end of use method
	
}//end of public class